﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using mkv16;

namespace mkv16
{
    public class InferenceEngine
    {
        public Source source;
        public Notion empty;

        public InferenceEngine()
        {
            source = new Source("Internal", "InferenceEngine");
            empty = new Notion(source);
        }

        public InferenceTree<Triple> FindInferences(Notion startingPoint, List<Triple> dictionary)
        {
            return FindInferences(startingPoint.Name, dictionary);
        }

        public InferenceTree<Triple> FindInferences(String startingPoint, List<Triple> dictionary)
        {
            var resultTree = new InferenceTree<Triple>();
            var matches = MatchSubject(startingPoint, dictionary);

            foreach (var triple in matches)
            {
                if (ExistsInParent(triple, resultTree) == false)
                {
                    var child = resultTree.AddChild(triple);
                    FindInferences(startingPoint, child, dictionary);
                }
            }

            resultTree.Value = new Triple(source, new Word(source, String.Empty), new Word(source, String.Empty), new Word(source, startingPoint)); 

            return resultTree;
        }

        public void FindInferences(String startingPoint, InferenceTree<Triple> tree, List<Triple> dictionary)
        {
            var searchTerm = tree.Value.Notion.Name;

            if (searchTerm == startingPoint)
                return;

            var matches = MatchSubject(searchTerm, dictionary);

            foreach (var triple in matches)
            {
                if (ExistsInParent(triple, tree) == false)
                {
                    var child = tree.AddChild(triple);
                    FindInferences(startingPoint, child, dictionary);
                }
            }
        }

        public static IEnumerable<Triple> MatchSubject(string word, IEnumerable<Triple> source)
        {
            var matches = from f in source
                          where f.Subject.Name == word
                          orderby f.Relation.Name, f.Subject.Name descending
                          select f;

            return matches;
        }

        public static IEnumerable<Triple> MatchNotion(string notion, IEnumerable<Triple> source)
        {
            var matches = from f in source
                          where f.Notion.Name == notion
                          orderby f.Relation.Name, f.Subject.Name descending
                          select f;

            return matches;
        }

        public static IEnumerable<Triple> MatchRelationNotion(string relation, string notion, IEnumerable<Triple> source)
        {
            var matches = from f in source
                          where f.Relation.Name == relation && f.Notion.Name == notion
                          orderby f.Relation.Name, f.Subject.Name descending
                          select f;

            return matches;
        }

        public static IEnumerable<Triple> MatchSubjectRelation(string subject, string relation, IEnumerable<Triple> source)
        {
            var matches = from f in source
                          where f.Subject.Name == subject && f.Relation.Name == relation
                          orderby f.Relation.Name, f.Subject.Name descending
                          select f;

            return matches;
        }

        public static IEnumerable<Triple> MatchSubjectNotion(string subject, string notion, IEnumerable<Triple> source)
        {
            var matches = from f in source
                          where f.Subject.Name == subject && f.Notion.Name == notion
                          orderby f.Relation.Name, f.Subject.Name descending
                          select f;

            return matches;
        }

        public bool ExistsInParent(Triple triple, InferenceTree<Triple> parent)
        {
            if (parent == null)
            {
                return false;
            }
            else
            {
                if (parent.Value == triple)
                {
                    return true;
                }
                else
                {
                    return ExistsInParent(triple, parent.Parent);
                }
            }
        }
    }
}
